Memory issues

Hello,

I'm trying to develop a script that would update three attributes then baseline the module. On certain modules the script runs out of memory and DOORS crashes. I believe this has to due with the volume of links that are being analysis(2-8K) and the way in which I'm writing the data to the attributes. Currently I can't any logic errors, if any. Any help would be greatly appreciated. Thank you.

-Jim
SystemAdmin - Thu Jan 17 13:41:03 EST 2013

Re: Memory issues
llandale - Thu Jan 17 15:59:02 EST 2013

[1] Yes, it could be the vast volumn of open modules. If so, you may have to violate the natural laws of nature and re-write your clever Attr-DXL such that it:
  • Runs and sets ALL objects in the module
    • for o in entire mod do
      • insert the body of your code here, changing "obj" to "o"
  • Remembers which other modules it opened; and at the end then close these modules

Then the attr-DXL actually only runs once. It would NOT run for the 2nd obj-attr values since it already has a value.

[2] Your "ProgressMessage" looks like a potential villian. That's a lot of concatenation and wasted string table space. Consider adding this:
  • if (cnt % 100 == 0) then progressMessage...
This it does that only every 100th object.

[3] Concatenating errmsg with the new message is theoretically rediculous; but with few errors it doesn't really matter. Instead use a buffer to accumulate your error message; bufEror += the new message.
  • string s = ""
  • for(i=0; i<1000; i++) s = s "A"
If I did my math correctly, you end up with a string of 1000 "A"s but use up 499,499 bytes in the string table (a string of 1000 "A"s plus a string of 999 "A"s pluse .. 998 + .. 1).

[4] On other news:
  • refreshDXLAttr should probably use for o in entire M do loop
  • That's the very first time I've ever seen anybody use that "set(attrTo, attrFrom)" command. Excellent.

-Louie

Re: Memory issues
SystemAdmin - Mon Jan 21 14:42:55 EST 2013

llandale - Thu Jan 17 15:59:02 EST 2013
[1] Yes, it could be the vast volumn of open modules. If so, you may have to violate the natural laws of nature and re-write your clever Attr-DXL such that it:

  • Runs and sets ALL objects in the module
    • for o in entire mod do
      • insert the body of your code here, changing "obj" to "o"
  • Remembers which other modules it opened; and at the end then close these modules

Then the attr-DXL actually only runs once. It would NOT run for the 2nd obj-attr values since it already has a value.

[2] Your "ProgressMessage" looks like a potential villian. That's a lot of concatenation and wasted string table space. Consider adding this:
  • if (cnt % 100 == 0) then progressMessage...
This it does that only every 100th object.

[3] Concatenating errmsg with the new message is theoretically rediculous; but with few errors it doesn't really matter. Instead use a buffer to accumulate your error message; bufEror += the new message.
  • string s = ""
  • for(i=0; i<1000; i++) s = s "A"
If I did my math correctly, you end up with a string of 1000 "A"s but use up 499,499 bytes in the string table (a string of 1000 "A"s plus a string of 999 "A"s pluse .. 998 + .. 1).

[4] On other news:
  • refreshDXLAttr should probably use for o in entire M do loop
  • That's the very first time I've ever seen anybody use that "set(attrTo, attrFrom)" command. Excellent.

-Louie

Hello,

When I trying to use the built-in wizard analysis and recursive depth of 4, DOORs is having memory issues then crashes. I was wondering what is the best way to analyis the links without without having DOORS crash? I was trying to modify the code from the wizard so that it would close the modules based on there depth but for some reason I can get my logic to work. Any help would be appreciated. Thank you.

-Jim

Re: Memory issues
SystemAdmin - Mon Jan 21 14:42:57 EST 2013

llandale - Thu Jan 17 15:59:02 EST 2013
[1] Yes, it could be the vast volumn of open modules. If so, you may have to violate the natural laws of nature and re-write your clever Attr-DXL such that it:

  • Runs and sets ALL objects in the module
    • for o in entire mod do
      • insert the body of your code here, changing "obj" to "o"
  • Remembers which other modules it opened; and at the end then close these modules

Then the attr-DXL actually only runs once. It would NOT run for the 2nd obj-attr values since it already has a value.

[2] Your "ProgressMessage" looks like a potential villian. That's a lot of concatenation and wasted string table space. Consider adding this:
  • if (cnt % 100 == 0) then progressMessage...
This it does that only every 100th object.

[3] Concatenating errmsg with the new message is theoretically rediculous; but with few errors it doesn't really matter. Instead use a buffer to accumulate your error message; bufEror += the new message.
  • string s = ""
  • for(i=0; i<1000; i++) s = s "A"
If I did my math correctly, you end up with a string of 1000 "A"s but use up 499,499 bytes in the string table (a string of 1000 "A"s plus a string of 999 "A"s pluse .. 998 + .. 1).

[4] On other news:
  • refreshDXLAttr should probably use for o in entire M do loop
  • That's the very first time I've ever seen anybody use that "set(attrTo, attrFrom)" command. Excellent.

-Louie

Hello,

When I trying to use the built-in wizard analysis and recursive depth of 4, DOORs is having memory issues then crashes. I was wondering what is the best way to analyis the links without without having DOORS crash? I was trying to modify the code from the wizard so that it would close the modules based on there depth but for some reason I can get my logic to work. Any help would be appreciated. Thank you.

-Jim

Re: Memory issues
llandale - Tue Jan 22 14:07:14 EST 2013

SystemAdmin - Mon Jan 21 14:42:55 EST 2013
Hello,

When I trying to use the built-in wizard analysis and recursive depth of 4, DOORs is having memory issues then crashes. I was wondering what is the best way to analyis the links without without having DOORS crash? I was trying to modify the code from the wizard so that it would close the modules based on there depth but for some reason I can get my logic to work. Any help would be appreciated. Thank you.

-Jim

To me, the wizard is almost hopeless at level 2 and a disaster any deeper. I don't think you have any mechanism for describing different link characteristics at the different levels and it seems likely you are opening LOTS of modules. If you query both in and out links then surely you are in an infinite loop in there somewhere.

Its also likely that you are displaying the target objects multiple times, one for every different link path you took to get there.

It is unrealistic to attempt to close modules in Layouts. The next object will just re-open them and you will end up thrashing.

If your schema looks like A->B->C->D then I'd suggest you are conceptualizing something incorrectly if you want A to display info about all the eventually linked D objects (e.g. why display all the "Unit" (B) level test procedures (A) in the System Spec (D)?).

-Louie

Re: Memory issues
SystemAdmin - Wed Jan 23 12:38:38 EST 2013

llandale - Tue Jan 22 14:07:14 EST 2013
To me, the wizard is almost hopeless at level 2 and a disaster any deeper. I don't think you have any mechanism for describing different link characteristics at the different levels and it seems likely you are opening LOTS of modules. If you query both in and out links then surely you are in an infinite loop in there somewhere.

Its also likely that you are displaying the target objects multiple times, one for every different link path you took to get there.

It is unrealistic to attempt to close modules in Layouts. The next object will just re-open them and you will end up thrashing.

If your schema looks like A->B->C->D then I'd suggest you are conceptualizing something incorrectly if you want A to display info about all the eventually linked D objects (e.g. why display all the "Unit" (B) level test procedures (A) in the System Spec (D)?).

-Louie

Hello,

Is there anyway of improving the below code for memory management and performance. Any help would be greatly appreciated?

-Jim
 

pragma runLim, 0
 
//Globals
Buffer bsz = create
const Regexp isPatt = regexp2 "^([^,]*),([^,]*),(.*)$"
const Regexp line = regexp2 ".*" // matches any character except newline
Skip Xopened = create
int cnt = 0
 
Module m = current
Object o = current(m)
 
void isVisibleXclose()
{
    //database cleanup...
        Module m = null
        for m in database do {
                if (!isVisible(m)) {
                        close(m)}
        }   
}
 
void CloseModules()
{
        if(cnt > 10) { // Max number of open modules...
                //initial call - remember modules already open  
                string modpath = null
                for modpath in Xopened do {
                        if(open(module modpath)) close(module item modpath)
                }
                setempty(Xopened); cnt = 0; modpath = null;
        }
}
 
string showIn(Object o, string depth) 
{
        bsz = ""
    Link l
    LinkRef lr
    ModName_ otherMod = null
    ModuleVersion otherVersion = null
    Object othero
    for lr in all(o<-"*") do {
        otherMod = module (sourceVersion lr)
        if (!null otherMod) {
            if ((!isDeleted otherMod) && (null data(sourceVersion lr))) {
                load((sourceVersion lr),false); put(Xopened, cnt++, fullName(module (sourceVersion lr)));
            }
        }
    }
    for l in all(o<-"*") do {
        otherVersion = sourceVersion l
        otherMod = module(otherVersion)
        if (null otherMod || isDeleted otherMod) continue
        othero = source l
        if (null othero) {load(otherVersion,false)}
        othero = source l
        if (null othero) continue
        if (isDeleted othero) continue
        bsz += depth; bsz += ","; bsz += fullName(module othero); bsz += ","; bsz += probeRichAttr_(othero,"Absolute Number", false); bsz += "\n";
    }
        depth = null
        CloseModules() // free all resources...
        string ret = stringOf(bsz)
        return(ret)
}
 
Object GOTObject(int absno, Module m)
{
        return(object(absno, m))
}
 
void wDir()
{
        string sourceDir = "c:\\AnalysisLinks"
        if(!fileExists_(sourceDir)) {
                mkdir(sourceDir)
        }
        sourceDir = null
}
 
void inputFile(Buffer &oldBuff, Buffer &newBuff, string level)
{ 
        string contents = stringOf(oldBuff)
        string str = null
        string temp = null
        bool printNOW = true
        Module m = null
        
        while (!null contents && line contents) {
                printNOW = true
                str = contents[match 0] // match 0 is whole of match
                
                if (isPatt str) {
                        //str[match 1]: depth
                        //str[match 2]: module
                        //str[match 3]: object
                        m = read(str[match 2], false); put(Xopened, cnt++, fullName(m));
                        if(null m) {
                                errorBox("{NULL} " str[match 2])
                        }
                        else {
                                if(level == "LEVEL1") {
                                        if(str[match 1] == "LEVEL1") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                } else if(level == "LEVEL2") {
                                        if(str[match 1] == "LEVEL1") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                } else if(level == "LEVEL3") {
                                        if(str[match 1] == "LEVEL2") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                } else if(str[match 1] == "LEVEL4") {
                                        if(level == "LEVEL4") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                }
                                if(printNOW) {
                                        newBuff += str; newBuff += "\n";
                                }
                        }
                }
                else {
                        errorBox("#error {input}: '"str"'")
                }
                str = null; temp = null;
                contents = contents[end 0 + 2:]  // move past newline
        }
        contents = null; level = null;
}
 
string nameM(string modpath) {
    return(name(module item modpath))
}
  
string replace (string sSource, string sSearch, string sReplace) {
//https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14892683&#14892683
 
    int iLen = length sSource
    if (iLen == 0) return("")
    
    int iLenSearch = length(sSearch)
    
    if (iLenSearch == 0) { 
        //raiseError ("Parameter error", "in strings.inc/replace: search string must not be empty")
        return("")
    }
    
    // read the first char for latter comparison -> speed optimization
    char firstChar = sSearch[0]
    
    Buffer s = create() 
    int pos = 0, d1, d2;    
    int i
    
    while (pos < iLen) { 
        char ch = sSource[pos]; 
        bool found = true
        
        if (ch != firstChar) {pos ++; s+= ch; continue}
        for (i = 1; i < iLenSearch; i++) {
           if (sSource[pos+i] != sSearch[i]) { found = false; break }
        }
        if (!found) {pos++; s+= ch; continue}
        s += sReplace
        pos += iLenSearch
    }
    
        sReplace = null
    string result = stringOf(s)
    delete s
    return(result)
}
 
string rMod(string contents)
{ 
        string str = contents
        
        while (!null contents && line contents) {
                if (isPatt contents) {
                        str = replace (str, contents[match 2], name(item contents[match 2])"")
                }
                contents = contents[end 0 + 2:]  // move past newline
        }
        contents = null
        return(str)
}
 
void main(Object cObj)
{
        int CASE = 0
        wDir()
        Buffer oldBuff =  create 
        oldBuff = ""
        Buffer newBuff = create
        newBuff = ""
 
        while(++CASE < 5) //Switch(case statement)
        {
                if(CASE == 1) {
                        oldBuff = showIn(current Object,"LEVEL1")
                                
                        isVisibleXclose() // free all resources...
                } else if(CASE == 2) {
                        //oldBuff = tempStringOf(oldBuff)
                        setempty(newBuff)
                        inputFile(oldBuff, newBuff, "LEVEL2")
                                
                        isVisibleXclose() // free all resources...
                } else if(CASE == 3) {
                        oldBuff = tempStringOf(newBuff)
                        setempty(newBuff)
                        inputFile(oldBuff, newBuff, "LEVEL3")
                        
                        isVisibleXclose() // free all resources...
                } else if(CASE == 4) {
                        oldBuff = tempStringOf(newBuff)
                        setempty(newBuff)
                        inputFile(oldBuff, newBuff, "LEVEL4")
                        
                        isVisibleXclose() // free all resources...
                } else {
                        warningBox("Default Case {" CASE "}")
                }
        }
 
        string sSource = stringOf(newBuff); delete oldBuff; delete newBuff;
        sSource = rMod(sSource)
        sSource = replace (sSource, "LEVEL1,", "")
        sSource = replace (sSource, "LEVEL2,", "\t")
        sSource = replace (sSource, "LEVEL3,", "\t\t")
        sSource = replace (sSource, "LEVEL4,", "\t\t\t")
        sSource = replace (sSource, ",", "-")
 
        Stream writtingBuf = write("c:\\AnalysisLinks\\final.txt")
                writtingBuf << sSource
                sSource = null
                close(writtingBuf)      
                
        delete isPatt
        delete line
        delete Xopened
        delete bsz
}
 
main(o); infoBox("done!");

Re: Memory issues
Mathias Mamsch - Wed Jan 23 15:52:43 EST 2013

SystemAdmin - Wed Jan 23 12:38:38 EST 2013

Hello,

Is there anyway of improving the below code for memory management and performance. Any help would be greatly appreciated?

-Jim
 

pragma runLim, 0
 
//Globals
Buffer bsz = create
const Regexp isPatt = regexp2 "^([^,]*),([^,]*),(.*)$"
const Regexp line = regexp2 ".*" // matches any character except newline
Skip Xopened = create
int cnt = 0
 
Module m = current
Object o = current(m)
 
void isVisibleXclose()
{
    //database cleanup...
        Module m = null
        for m in database do {
                if (!isVisible(m)) {
                        close(m)}
        }   
}
 
void CloseModules()
{
        if(cnt > 10) { // Max number of open modules...
                //initial call - remember modules already open  
                string modpath = null
                for modpath in Xopened do {
                        if(open(module modpath)) close(module item modpath)
                }
                setempty(Xopened); cnt = 0; modpath = null;
        }
}
 
string showIn(Object o, string depth) 
{
        bsz = ""
    Link l
    LinkRef lr
    ModName_ otherMod = null
    ModuleVersion otherVersion = null
    Object othero
    for lr in all(o<-"*") do {
        otherMod = module (sourceVersion lr)
        if (!null otherMod) {
            if ((!isDeleted otherMod) && (null data(sourceVersion lr))) {
                load((sourceVersion lr),false); put(Xopened, cnt++, fullName(module (sourceVersion lr)));
            }
        }
    }
    for l in all(o<-"*") do {
        otherVersion = sourceVersion l
        otherMod = module(otherVersion)
        if (null otherMod || isDeleted otherMod) continue
        othero = source l
        if (null othero) {load(otherVersion,false)}
        othero = source l
        if (null othero) continue
        if (isDeleted othero) continue
        bsz += depth; bsz += ","; bsz += fullName(module othero); bsz += ","; bsz += probeRichAttr_(othero,"Absolute Number", false); bsz += "\n";
    }
        depth = null
        CloseModules() // free all resources...
        string ret = stringOf(bsz)
        return(ret)
}
 
Object GOTObject(int absno, Module m)
{
        return(object(absno, m))
}
 
void wDir()
{
        string sourceDir = "c:\\AnalysisLinks"
        if(!fileExists_(sourceDir)) {
                mkdir(sourceDir)
        }
        sourceDir = null
}
 
void inputFile(Buffer &oldBuff, Buffer &newBuff, string level)
{ 
        string contents = stringOf(oldBuff)
        string str = null
        string temp = null
        bool printNOW = true
        Module m = null
        
        while (!null contents && line contents) {
                printNOW = true
                str = contents[match 0] // match 0 is whole of match
                
                if (isPatt str) {
                        //str[match 1]: depth
                        //str[match 2]: module
                        //str[match 3]: object
                        m = read(str[match 2], false); put(Xopened, cnt++, fullName(m));
                        if(null m) {
                                errorBox("{NULL} " str[match 2])
                        }
                        else {
                                if(level == "LEVEL1") {
                                        if(str[match 1] == "LEVEL1") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                } else if(level == "LEVEL2") {
                                        if(str[match 1] == "LEVEL1") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                } else if(level == "LEVEL3") {
                                        if(str[match 1] == "LEVEL2") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                } else if(str[match 1] == "LEVEL4") {
                                        if(level == "LEVEL4") {
                                                temp = showIn(GOTObject(intOf(realOf(str[match 3]"")), m),level)
                                                if(!null temp) {
                                                        newBuff += str; newBuff += "\n"; newBuff += temp;
                                                        printNOW = false
                                                }
                                        }
                                }
                                if(printNOW) {
                                        newBuff += str; newBuff += "\n";
                                }
                        }
                }
                else {
                        errorBox("#error {input}: '"str"'")
                }
                str = null; temp = null;
                contents = contents[end 0 + 2:]  // move past newline
        }
        contents = null; level = null;
}
 
string nameM(string modpath) {
    return(name(module item modpath))
}
  
string replace (string sSource, string sSearch, string sReplace) {
//https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14892683&#14892683
 
    int iLen = length sSource
    if (iLen == 0) return("")
    
    int iLenSearch = length(sSearch)
    
    if (iLenSearch == 0) { 
        //raiseError ("Parameter error", "in strings.inc/replace: search string must not be empty")
        return("")
    }
    
    // read the first char for latter comparison -> speed optimization
    char firstChar = sSearch[0]
    
    Buffer s = create() 
    int pos = 0, d1, d2;    
    int i
    
    while (pos < iLen) { 
        char ch = sSource[pos]; 
        bool found = true
        
        if (ch != firstChar) {pos ++; s+= ch; continue}
        for (i = 1; i < iLenSearch; i++) {
           if (sSource[pos+i] != sSearch[i]) { found = false; break }
        }
        if (!found) {pos++; s+= ch; continue}
        s += sReplace
        pos += iLenSearch
    }
    
        sReplace = null
    string result = stringOf(s)
    delete s
    return(result)
}
 
string rMod(string contents)
{ 
        string str = contents
        
        while (!null contents && line contents) {
                if (isPatt contents) {
                        str = replace (str, contents[match 2], name(item contents[match 2])"")
                }
                contents = contents[end 0 + 2:]  // move past newline
        }
        contents = null
        return(str)
}
 
void main(Object cObj)
{
        int CASE = 0
        wDir()
        Buffer oldBuff =  create 
        oldBuff = ""
        Buffer newBuff = create
        newBuff = ""
 
        while(++CASE < 5) //Switch(case statement)
        {
                if(CASE == 1) {
                        oldBuff = showIn(current Object,"LEVEL1")
                                
                        isVisibleXclose() // free all resources...
                } else if(CASE == 2) {
                        //oldBuff = tempStringOf(oldBuff)
                        setempty(newBuff)
                        inputFile(oldBuff, newBuff, "LEVEL2")
                                
                        isVisibleXclose() // free all resources...
                } else if(CASE == 3) {
                        oldBuff = tempStringOf(newBuff)
                        setempty(newBuff)
                        inputFile(oldBuff, newBuff, "LEVEL3")
                        
                        isVisibleXclose() // free all resources...
                } else if(CASE == 4) {
                        oldBuff = tempStringOf(newBuff)
                        setempty(newBuff)
                        inputFile(oldBuff, newBuff, "LEVEL4")
                        
                        isVisibleXclose() // free all resources...
                } else {
                        warningBox("Default Case {" CASE "}")
                }
        }
 
        string sSource = stringOf(newBuff); delete oldBuff; delete newBuff;
        sSource = rMod(sSource)
        sSource = replace (sSource, "LEVEL1,", "")
        sSource = replace (sSource, "LEVEL2,", "\t")
        sSource = replace (sSource, "LEVEL3,", "\t\t")
        sSource = replace (sSource, "LEVEL4,", "\t\t\t")
        sSource = replace (sSource, ",", "-")
 
        Stream writtingBuf = write("c:\\AnalysisLinks\\final.txt")
                writtingBuf << sSource
                sSource = null
                close(writtingBuf)      
                
        delete isPatt
        delete line
        delete Xopened
        delete bsz
}
 
main(o); infoBox("done!");

Well two things come to me from a first glance:
 

  • You are leaking a ton of ModuleVersion objects in your code. Depending on how often you call showObject in your code, this can make your code run out of memory. One of my traceability scripts had exactly this problem and it could be run through the complete database after removing the leaked ModuleVersions. With ModuleVersions it is especially dangarous, since any Assignment outside a declaration will create a new leaked object. So your showObject Code should be like this:


You can find details regarding the ModuleVersion problem here: https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14832712&#14832712

 

 

string showIn(Object o, string depth) 
{
    bsz = ""
    Link l
    LinkRef lr
    ModName_ otherMod = null
 
    ModuleVersion otherVersion = null
    Object othero
    for lr in all(o<-"*") do {
            ModuleVersion mvSource = sourceVersion lr
        otherMod = module mvSource
        if (!null otherMod) {
            if ((!isDeleted otherMod) && (null data(mvSource))) {
                load((mvSource),false); put(Xopened, cnt++, fullName(module (mvSource)));
            }
        }
                delete mvSource
    }
        
    for l in all(o<-"*") do {
        ModuleVersion otherVersion = sourceVersion l // Use assignment in declaration, otherwise: Leak
        otherMod = module(otherVersion)
        if (null otherMod || isDeleted otherMod) { delete otherVersion; continue }
        othero = source l
        if (null othero) {load(otherVersion,false)}
        othero = source l
        if (null othero) { delete otherVersion; continue }
        if (isDeleted othero) { delete otherVersion; continue }
        bsz += depth; bsz += ","; bsz += fullName(module othero); bsz += ","; bsz += probeRichAttr_(othero,"Absolute Number", false); bsz += "\n";
                delete otherVersion
    }
        depth = null
        CloseModules() // free all resources...
        string ret = stringOf(bsz)
        return(ret)
}

 

 

 

 

  • The second problem I see is, that the code

 

 

Module m
for m in database do { close m }

 


does not work reliably, due to the 'do not delete from something you are iterating over' rule. I went into some length once to get a reliable tracking of opened modules and being able to close them, and I have one conclusion. If you want a rock solid code, that will run over complete databases without breaking down even in the worst cases, open only one module, read the data, store it, close the module. If that is infeasible since you only want to have a small script, which does not care about caching tons of data, then keep very good track of each module you open and close. Do not use for Module in database.

Maybe this helps, regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS